﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Net;
using System.IO;
using System.Windows.Forms;
using System.ComponentModel;

namespace ProxyList
{
    delegate void ShowInfo(ProxyInfo State);

    // передаваемый аргумент  - ProxyInfo Info
    public delegate void AfterProxyCheck(object Info);
    // передаваемый аргумент  - null
    public delegate void WorkComplete(object Info);

    class CheckerManager
    {
        public event AfterProxyCheck onCheck = null;
        public event WorkComplete onComplete = null;
        public string URL = String.Empty;

        private AsyncOperation Operation = null;

        private const int POOL_SIZE = 5;
        private volatile int WorkedCount = 0;
        private volatile bool doBreak = false;
        private Thread starter = null;

        private List<Checker> checkers = null;

        public CheckerManager()
        {
            checkers = new List<Checker>();
        }

        // метод выполняется в рабочем потоке
        public void WorkerThread(AsyncOperation AsyncOper)
        {
            Operation = AsyncOper;
            starter = Thread.CurrentThread;

            List<ProxyInfo> proxies = AsyncOper.UserSuppliedState as List<ProxyInfo>;

            checkers.Clear();
            doBreak = false;
            WorkedCount = 0;

            for (int i = 0; i < proxies.Count; i++)
            {
                if (doBreak)
                {
                    while (checkers.Count > 0) 
                        checkers[0].Stop();
                    break;
                }

                // если параллельных потоков запущено меньше, 
                // чем допустимо, то запускаем еще
                if (WorkedCount < POOL_SIZE)
                {
                    lock (checkers)
                    {
                        Checker checker = new Checker(URL, proxies[i], UpdateProxy);
                        checkers.Add(checker);
                        AsyncOperation ao = AsyncOperationManager.CreateOperation(proxies[i]);
                        new AsyncOperationInvoker(checker.Execute).BeginInvoke(ao, null, null);

                        WorkedCount++;
                    }
                }
                // иначе усыпляем поток
                else
                {
                    Thread.Sleep(500);
                    i--;
                }
            }
            Console.WriteLine("Прокси-лист кончился. Работает: {0}", WorkedCount);
            Complete();
        }

        public void UpdateProxy(object Info)
        {
            SendOrPostCallback callback = delegate(object Obj)
            {
                if (onCheck != null) onCheck(Obj);
            };

            WorkedCount--;
            Operation.Post(callback, Info);
            ProxyInfo info = Info as ProxyInfo;
            Console.WriteLine("[{0}] закончил. Осталось: {1}", info.Address, WorkedCount);
        }

        private void Complete()
        {
            SendOrPostCallback callback = delegate(object Obj)
            {
                if (onComplete != null) onComplete(Obj);
            };

            Console.WriteLine("Работа завершена ждем всех. Осталось {0} чекеров", WorkedCount);
            while (WorkedCount > 0) Thread.Sleep(100);
            Console.WriteLine("Все чекеры завершили работу");
            Operation.Post(callback, null);
        }

        internal void Stop()
        {
            doBreak = true;
            Complete();
            //starter.Abort();
            // starter.Join();
        }
    }
}
